﻿namespace NJQuery {
	using System;

	/// <summary>
	/// Defines a client stylesheet to be registered with the jQuery <see cref="Manager"/> by various server controls.
	/// These entries are used to look up URLs in the <see cref="Configuration.ClientStylesSection" /> of the config file or, in absence, to generate a default relative URL.
	/// </summary>
	public struct ClientStyle : IEquatable<ClientStyle> {


		#region Static Fields: Combined Style Definitions

		private static readonly ClientStyle uiUnified = Settings.Current.ClientStyles.References.Contains("jquery.ui") ? new ClientStyle("jquery.ui") : new ClientStyle();

		#endregion


		#region Static Fields: Style Definitions

		/// <summary>
		/// The core stylesheet shared by the <see href="http://jqueryui.com/">jQuery UI</see> framework.
		/// </summary>
		public static readonly ClientStyle UICore = new ClientStyle("jquery.ui.core", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/accordion/">jQuery UI Accordion widget</see>.
		/// </summary>
		public static readonly ClientStyle UIAccordionWidget = new ClientStyle("jquery.ui.accordion", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/autocomplete/">jQuery UI Autocomplete widget</see>.
		/// </summary>
		public static readonly ClientStyle UIAutoCompleteWidget = new ClientStyle("jquery.ui.autocomplete", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/button/">jQuery UI Button widget</see>.
		/// </summary>
		public static readonly ClientStyle UIButtonWidget = new ClientStyle("jquery.ui.button", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/datepicker/">jQuery UI Datepicker widget</see>.
		/// </summary>
		public static readonly ClientStyle UIDatePickerWidget = new ClientStyle("jquery.ui.datepicker", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/dialog/">jQuery UI Dialog widget</see>.
		/// </summary>
		public static readonly ClientStyle UIDialogWidget = new ClientStyle("jquery.ui.dialog", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/progressbar/">jQuery UI Progressbar widget</see>.
		/// </summary>
		public static readonly ClientStyle UIProgressBarWidget = new ClientStyle("jquery.ui.progressbar", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/slider/">jQuery UI Slider widget</see>.
		/// </summary>
		public static readonly ClientStyle UISliderWidget = new ClientStyle("jquery.ui.slider", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/tabs/">jQuery UI Tabs widget</see>.
		/// </summary>
		public static readonly ClientStyle UITabsWidget = new ClientStyle("jquery.ui.tabs", uiUnified.name);

		/// <summary>
		/// The stylesheet used by the <see href="http://jqueryui.com/demos/resizable/">jQuery UI Resizable interaction</see>.
		/// </summary>
		public static readonly ClientStyle UIResizableInteraction = new ClientStyle("jquery.ui.resizable", uiUnified.name);

		#endregion


		#region Fields

		private string name;
		private string substituteName;

		#endregion


		#region Constructors

		/// <summary>
		/// Creates a new instance of the <see cref="ClientStyle"/> structure with no substitution.
		/// </summary>
		/// <param name="name">The invariant name of the stylesheet.</param>
		public ClientStyle(string name) : this(name, null) { }

		/// <summary>
		/// Creates a new instance of the <see cref="ClientStyle"/> structure with an optional subtitution allowing multiple logical stylesheets to be combined into a single combined stylesheet.
		/// </summary>
		/// <param name="name">The invariant name of the stylesheet.</param>
		/// <param name="substituteName">The invariant name of a combined stylesheet used in place of the atomic logical stylesheet represented by the instance.</param>
		public ClientStyle(string name, string substituteName) {
			if(name == null) throw new ArgumentNullException("name");
			if(name.Length == 0) throw new ArgumentException("Name must have a value.", "name");

			this.name = name;
			this.substituteName = substituteName;
		}

		#endregion


		#region Properties

		/// <summary>
		/// Gets the invariant name of the stylesheet.
		/// </summary>
		public string Name {
			get { return name; }
		}

		/// <summary>
		/// Gets the invariant name of a combined stylesheet used in place of the atomic logical stylesheet represented by the instance.
		/// </summary>
		public string SubstituteName {
			get { return substituteName; }
		}

		/// <summary>
		/// Gets the invariant name that will be used by the jQuery <see cref="Manager"/> to create the dynamic list of unique stylesheets for the page.
		/// </summary>
		public string RegisterName {
			get {
				if(!string.IsNullOrEmpty(substituteName)) return substituteName;
				return name;
			}
		}

		/// <summary>
		/// Gets whether or not the instance has a no value.
		/// </summary>
		public bool IsEmpty {
			get { return name == null; }
		}

		#endregion


		#region Methods: Object management

		/// <summary>
		/// Determines whether or not the specified object is equal to the current <see cref="ClientStyle"/> value.
		/// </summary>
		/// <param name="obj">The <see cref="Object"/> to compare.</param>
		/// <returns>Whether or not the provided object is equal.</returns>
		public override bool Equals(object obj) {
			if(obj is ClientStyle) return this == (ClientStyle)obj;
			return false;
		}

		/// <summary>
		/// Determines whether or not the specified ClientStyle is equal to the current <see cref="ClientStyle"/> value.
		/// </summary>
		/// <param name="other">The <see cref="ClientStyle"/> to compare.</param>
		/// <returns>Whether or not the provided <see cref="ClientStyle"/> value is equal.</returns>
		public bool Equals(ClientStyle other) {
			return this == other;
		}

		/// <summary>
		/// Serves as a hash function for <see cref="ClientStyle"/>.
		/// </summary>
		/// <returns>The hash value associated with the contained data.</returns>
		public override int GetHashCode() {
			if(IsEmpty) return 0;
			return RegisterName.GetHashCode();
		}

		/// <summary>
		/// Returns a <see cref="String"/> that represents the current <see cref="ClientStyle"/> value.
		/// </summary>
		/// <returns>The string representation.</returns>
		public override string ToString() {
			if(IsEmpty) return string.Empty;
			return RegisterName.ToString();
		}

		/// <summary>
		/// Returns a literal JavaStyle value used to represent the server value on the client.
		/// </summary>
		/// <returns>The client Style value.</returns>
		public string ToClientSource() {
			if(IsEmpty) return ScriptBuilder.NullLiteral;
			return RegisterName.ToClientSource();
		}

		#endregion


		#region Operators

		/// <summary>
		/// Compares the equality of two <see cref="ClientStyle"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two values are equal.</returns>
		public static bool operator ==(ClientStyle value0, ClientStyle value1) {
			return value0.IsEmpty == value1.IsEmpty && value0.RegisterName == value1.RegisterName;
		}

		/// <summary>
		/// Compares the inequality of two <see cref="ClientStyle"/> values.
		/// </summary>
		/// <param name="value0">The first value.</param>
		/// <param name="value1">The second value.</param>
		/// <returns>Whether or not the two values are distinct.</returns>
		public static bool operator !=(ClientStyle value0, ClientStyle value1) {
			return value0.IsEmpty != value1.IsEmpty || value0.RegisterName != value1.RegisterName;
		}

		#endregion


	}

}